/**
 * @file heap.h
 * @author LokLiang (lokliang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-01
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __HEAP_H__
#define __HEAP_H__

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C"
{
#endif

size_t _cpu_clz(size_t val); // 计算前导零

void *__malloc(size_t size);
void *__calloc(size_t nmemb, size_t size);
void *__realloc(void *ptr, size_t size);
void __free(void *ptr);

typedef void (*heap_critical_entry_fn)(void);
typedef void (*heap_critical_exit_fn)(void);

void heap_port_init(heap_critical_entry_fn entry_critical, heap_critical_exit_fn exit_critical);
void heap_entry_critical(void);
void heap_exit_critical(void);

typedef struct
{
    void *handle;
} heap_t;

extern heap_t g_heap_default_handle;

int heap_init(heap_t *heap_handle, void *mem_base, unsigned mem_size); // 初始化一个内存空间为内存

void *heap_malloc      (heap_t *heap_handle, unsigned size);          // 申请内存
void *heap_calloc      (heap_t *heap_handle, unsigned size);          // 申请内存并置0
void *heap_malloc_tail (heap_t *heap_handle, unsigned size);          // 申请内存；优先从空闲块的尾部申请
void *heap_calloc_tail (heap_t *heap_handle, unsigned size);          // 申请内存并置0；优先从空闲块的尾部申请
void *heap_realloc     (heap_t *heap_handle, void *p, unsigned size); // 重定义已申请的内存大小
void  heap_free        (heap_t *heap_handle, void *p);                // 释放内存
void  heap_free_all    (heap_t *heap_handle);                         // 释放所有内存

bool heap_is_valid(heap_t *heap_handle, void *p); // 获取内存指针是否有效

unsigned heap_block_size (void *p); // 已申请内存块的实际占用空间大小（不含所有控制信息）（字节）
unsigned heap_space_size (void *p); // 已申请内存块的实际占用空间大小（含所有控制信息）（字节）

void *heap_get_base (heap_t *heap_handle); // 获取用户定义的内存的基地址
void *heap_get_end  (heap_t *heap_handle); // 获取用户定义的内存的结束地址

unsigned heap_used_size  (heap_t *heap_handle); // 获取总已使用空间
unsigned heap_free_size  (heap_t *heap_handle); // 获取总空闲空间（包含所有碎片）
unsigned heap_block_max  (heap_t *heap_handle); // 获取当前最大的连续空间

unsigned heap_header_size(void); // 堆的头信息消耗的字节数
unsigned heap_mblock_size(void); // 每个管理块额外消耗的字节数

int heap_info(heap_t *heap_handle, size_t *dst_used, size_t *dst_free, size_t *dst_max_block); // 获取堆的空间信息

typedef struct
{
    void *handle;
} heapk_t;

int  heapk_create    (heapk_t *heapk_handle, heap_t *heap_handle, int lists); // 创建一个散列表
void heapk_heap_base (heapk_t *heapk_handle, heap_t *heap_handle);            // 查询散列表依赖的堆的句柄
void heapk_delete    (heapk_t *heapk_handle);                                 // 删除散列表

void *heapk_malloc   (heapk_t *heapk_handle, int mem_size, const void *key_base, uint8_t key_size); // 在散列表中申请一个带映射键值的内存。
void  heapk_clr_key  (void *p);                                                                     // 只删除关键字，但所申请的内存依然保留并可用
void  heapk_free     (void *p);                                                                     // 由 heapk_CreateTab() 所申请获得的指针
void  heapk_free_all (heapk_t *heapk_handle);                                                       // 释放所有内存

void heapk_list_reset (heapk_t *heapk_handle);                                                                        // 重置列举指针
bool heapk_list_next  (heapk_t *heapk_handle, void **store_mem_base, void **store_key_base, uint8_t *store_key_size); // 列举下个已申请的内存信息

bool    heapk_is_valid   (void *p);                                                       // 获取内存指针是否有效
void   *heapk_block_base (heapk_t *heapk_handle, const void *key_base, uint8_t key_size); // 通过键值查找 heapk_malloc() 的申请的内存地址
int     heapk_block_size (void *p);                                                       // 通过内存封装地址获取 heapk_malloc() 申请时设定的内存大小
int     heapk_space_size (void *p);                                                       // 已申请内存块的实际占用空间大小（含所有控制信息）（字节）
void   *heapk_key_base   (void *p);                                                       // 通过内存封装地址获取 heapk_malloc() 申请时设定的键值地址
uint8_t heapk_key_size   (void *p);                                                       // 通过内存封装地址获取 heapk_malloc() 申请时设定的键值的有效字节数

#ifdef __cplusplus
}
#endif

#endif
